home *** CD-ROM | disk | FTP | other *** search
/ The Best of MacTutor - S…e Code for Volumes 1 to 5 / The Best of MacTutor - Source Code for Volume 1-5 (Wayzata Technology)(6031)(1990).bin / Source Code / #41 (Feb 89) / security code / Globals.p < prev    next >
Text File  |  1988-11-29  |  35KB  |  1,485 lines

  1. UNIT  Globals;
  2. {-------------------------------------------}
  3. (*
  4. ©1988 by Steve Seaquist. All rights reserved.
  5. Used by permission.  Use at your own risk.  
  6. No warranty is expressed or implied.  
  7.  
  8. This Macintosh virus-detecting program was 
  9. originally published and explained in the 
  10. February 1989 issue of MacTutor magazine.  
  11. Some aspects of its design are important to 
  12. security, and it uses some unusual 
  13. techniques, so please read the article.  
  14. *)
  15. {-------------------------------------------}
  16. INTERFACE
  17. USES
  18.   MemTypes,QuickDraw,OSIntf,ToolIntf,
  19.   PackIntf;
  20.  
  21. CONST
  22.   {---- Low Mem Globals ----}
  23.   kCurApName          = $910;
  24.   kCurApRefNum        = $900;
  25.   kBootDrive          = $210;
  26.   kResLoad            = $A5E;
  27.   kScrDmpEnb          = $2F8;
  28.   kSFCBLen            = $3F6;
  29.   kSPConfig           = $1FB;
  30.   kSysMap             = $A58;
  31.   kSysResName         = $AD8;
  32.   {---- Other constants ----}
  33.   kIOBufferSize       = 10000;
  34.   kProcessSelf        = FALSE;
  35.   kRsrcHdlValid       = 9876543;
  36.   kRsrcIsInitd        = 3456789;
  37.   kZeroOutVirs        = TRUE;
  38.  
  39. TYPE
  40.   TCountsPtr          = ^TCountsRec;
  41.   TCountsRec          =
  42.     RECORD
  43.     fDeleted:         LONGINT;
  44.     fExamined:        LONGINT;
  45.     fFiles:           LONGINT;
  46.     fInfected:        LONGINT;
  47.     fRemoved:         LONGINT;
  48.     fResources:       LONGINT;
  49.     END;
  50.  
  51.   TFeedbackPtr        = ^TFeedbackRec;
  52.   TFeedbackRec        =
  53.     PACKED RECORD
  54.     fWroteDirname:    BOOLEAN;
  55.     fWroteFilename:   BOOLEAN;
  56.     END;
  57.  
  58.   TJTEHdl             = ^TJTEPtr;
  59.   TJTEPtr             = ^TJTERec;
  60.   TJTERec             =
  61.     RECORD
  62.     fOffset:          INTEGER;
  63.     fSkip3F3C:        INTEGER;
  64.     fSegId:           INTEGER;
  65.     fSkipA9F0:        INTEGER;
  66.     END;
  67.  
  68.   TJTHdl              = ^TJTPtr;
  69.   TJTPtr              = ^TJTRec;
  70.   TJTRec              =
  71.     RECORD
  72.     fAboveA5Size:     LONGINT;
  73.     fBelowA5Size:     LONGINT;
  74.     fNbrBytesInTable: LONGINT;
  75.     fTableOffset:     LONGINT;
  76.     fJTEntry:         
  77.       ARRAY [1..1] OF TJTERec;
  78.     END;
  79.  
  80.   TLoaded             = 
  81.     (eNotYet,eAlreadyLoaded,eWeLoadedIt);
  82.  
  83.   TMainItem           = 
  84.     (eNotADlogItem,
  85.     eDirs,eDiry,eEvery,eFiles,eQuit,
  86.     eAwait,eBeeps,eFgPr,eFgPrC,
  87.     eLList,eRmVir,eTrace,
  88.     eMain,eOpts,eScOW, 
  89.     eDBtn);
  90.   TMainOpt            = 
  91.     ARRAY [eAwait..eTrace] OF BOOLEAN;
  92.  
  93.   TPaocRec            = 
  94.     PACKED ARRAY[1..1] OF CHAR;
  95.   TResIdOrIndex       = (ResId,Index);
  96.  
  97.   TRsrcPtr            = ^TRsrcRec;
  98.   TRsrcRec            =
  99.     RECORD
  100.     fFlag:            LONGINT;
  101.     fHdl:             Handle;
  102.     fInfected:        BOOLEAN;
  103.     fKnown:           BOOLEAN;
  104.     fLoaded:          TLoaded;
  105.     fResAttrs:        INTEGER;
  106.     fResId:           INTEGER;
  107.     fResType:         ResType;
  108.     fSize:            Size;
  109.     fState:           SignedByte;
  110.     END;
  111.  
  112.   TScoresHdl          = ^TScoresPtr;
  113.   TScoresPtr          = ^TScoresRec;
  114.   TScoresRec          =
  115.     RECORD
  116.     fOffsetToFirstJTE:INTEGER;
  117.     fNbrJTEsForRsrc:  INTEGER;
  118.     fOldJTE:          TJTERec;
  119.     END;
  120.  
  121.   TWordHdl            = ^TWordPtr;
  122.   TWordPtr            = ^INTEGER;
  123.  
  124. VAR
  125.   gAAGlobals:         SignedByte;
  126.   gAbortPatrol:       BOOLEAN;
  127.   gActiveSelf:        BOOLEAN;
  128.   gActiveSys:         BOOLEAN;
  129.   gCode0:             TRsrcRec;
  130.   gCounts:            TCountsRec;
  131.   gCurrDInfo:         DInfo;
  132.   gCurrDirId:         LONGINT;
  133.   gCurrDirname:       Str255;
  134.   gCurrEOF:           LONGINT;
  135.   gCurrIOBuffer:      Ptr;
  136.   gCurrFileDeleted:   BOOLEAN;
  137.   gCurrFilename:      Str255;
  138.   gCurrFInfo:         FInfo;
  139.   gCurrIndex:         INTEGER;
  140.   gCurrRefNum:        INTEGER;
  141.   gCurrRsrc:          TRsrcRec;
  142.   gCurrVRefNum:       INTEGER;
  143.   gCurrWDRefNum:      INTEGER;
  144.   gDateTimeRec:       DateTimeRec;
  145.   gDisabled:          TMainOpt;
  146.   gDlogPtr:           DialogPtr;
  147.   gError:             OSErr;
  148.   gEvt:               EventRecord;
  149.   gEvtMask:           INTEGER;
  150.   gFgPrTitle:         Str255;
  151.   gGrafPtr:           GrafPtr;
  152.   gHFS:               BOOLEAN;
  153.   gInd:               STRING[10];
  154.   gInfected:          BOOLEAN;
  155.   gInfectedWritten:   BOOLEAN;
  156.   gOption:            TMainOpt;
  157.   gPgmrname:          Str255;
  158.   gReportFlags:       TFeedbackRec;
  159.   gScreenFlags:       TFeedbackRec;
  160.   gSecsBegins:        LONGINT;
  161.   gSecsEnds:          LONGINT;
  162.   gSFGetPt:           Point;
  163.   gSFPutPt:           Point;
  164.   gSFRep:             SFReply;
  165.   gTotals:            TCountsRec;
  166.   gZZGlobals:         SignedByte;
  167.  
  168. FUNCTION   Code0IsValid
  169.   :          BOOLEAN;
  170. PROCEDURE  CommentBegins;
  171. PROCEDURE  CommentFgPrRsrc
  172.   (pRsrcPtr: TRsrcPtr);
  173. PROCEDURE  CommentRsrcBegins
  174.   (pRsrcPtr: TRsrcPtr);
  175. PROCEDURE  DirectoryBegins;
  176. PROCEDURE  DirectoryEnds;
  177. PROCEDURE  ErrorBegins
  178.   (pStr:     Str255);
  179. PROCEDURE  ErrorEnds
  180.   (pBeeps:   INTEGER);
  181. PROCEDURE  ErrorOSErr
  182.   (pStr:     Str255);
  183. PROCEDURE  GetRsrc
  184.   (pRsrcPtr: TRsrcPtr;
  185.   pResType:  ResType;
  186.   pInt:      INTEGER;
  187.   pIntIs:    TResIdOrIndex);
  188. PROCEDURE  InitGlobals;
  189. PROCEDURE  InitRsrc
  190.   (pRsrcPtr: TRsrcPtr);
  191. FUNCTION   JTEIsValid
  192.   (pJTEPtr:  TJTEPtr)
  193.   :          BOOLEAN;
  194. PROCEDURE  ListCounts
  195.   (pPtr:     TCountsPtr);
  196. PROCEDURE  LookForKnownViruses;
  197. PROCEDURE  PauseBriefly;
  198. PROCEDURE  PatrolBegins;
  199. PROCEDURE  PatrolEnds;
  200. PROCEDURE  ProcessCurrRsrc;
  201. PROCEDURE  ProcessFile;
  202. PROCEDURE  ReleaseRsrc
  203.   (pRsrcPtr: TRsrcPtr);
  204. PROCEDURE  ShortHexDump
  205.   (pPtr:     Ptr;
  206.   pNbrBytes: SignedByte);
  207. PROCEDURE  Trace
  208.   (pStr:    Str255);
  209. PROCEDURE  TraceNbr
  210.   (pStr:     Str255;
  211.   pNbr:      LONGINT);
  212. PROCEDURE  ZeroOut
  213.   (pStart:   Ptr;
  214.   pCount:    Size);
  215. PROCEDURE  ZeroOutRange
  216.   (p1:       Ptr;
  217.   p2:        Ptr);
  218.  
  219. {*******************************************}
  220. IMPLEMENTATION
  221. {$R-}
  222.  
  223. PROCEDURE  ExitSecurityPatrol;      EXTERNAL;
  224. PROCEDURE  Wryte
  225.   (pStr:     Str255);               EXTERNAL;
  226. PROCEDURE  WryteChar
  227.   (pChar:    CHAR);                 EXTERNAL;
  228. PROCEDURE  WryteEoln;               EXTERNAL;
  229. PROCEDURE  WryteFilename;           EXTERNAL;
  230. PROCEDURE  WryteFilenameToScreenOnlyForNow;
  231.                                     EXTERNAL;
  232. PROCEDURE  WryteLn
  233.   (pStr:     Str255);               EXTERNAL;
  234. PROCEDURE  WryteNbr
  235.   (pNbr:     LONGINT;
  236.   pNbrDigits:INTEGER);              EXTERNAL;
  237. PROCEDURE  WryteType
  238.   (pType:    ResType);              EXTERNAL;
  239.  
  240. PROCEDURE  CallProcPtr
  241.   (pProcPtr: ProcPtr);
  242. INLINE
  243.   $205F,     { MOVE.L (A7)+,A0 }
  244.   $4E90;     { JSR    (A0)     }
  245.  
  246. PROCEDURE  ErrorInfected
  247.   (pStr:     Str255);                FORWARD;
  248. PROCEDURE  ErrorMsg
  249.   (pStr:     Str255;
  250.   pBeeps:    INTEGER);               FORWARD;
  251. FUNCTION   FixedCode0
  252.   (pJTPtr:   TJTEPtr)
  253.   :          BOOLEAN;                FORWARD;
  254. PROCEDURE  ProcessRsrcs
  255.   (pResType: ResType;
  256.   pProcPtr:  ProcPtr);               FORWARD;
  257. FUNCTION   RemovedRsrc
  258.   (pRsrcPtr: TRsrcPtr)
  259.   :          BOOLEAN;                FORWARD;
  260. PROCEDURE  TraceRsrc
  261.   (pStr:     Str255;
  262.   pRsrcPtr:  TRsrcPtr);              FORWARD;
  263.  
  264. {$S Fingerprint}
  265. {$I Fingerprint.ipas }
  266. {$S Globals}
  267. {-------------------------------------------}
  268. PROCEDURE  AbortPatrolIfCmdPeriodPressed;
  269. BEGIN
  270. WHILE GetNextEvent(gEvtMask,gEvt) DO
  271.   WITH gEvt DO
  272.     IF  (what = nullEvent) THEN
  273.       LEAVE
  274.     ELSE IF (what = keyDown) THEN
  275.       IF  (BAnd(modifiers,cmdKey)=cmdKey)
  276.       AND (BAnd(message,charCodeMask)=$2E)
  277.       THEN
  278.         BEGIN
  279.         gAbortPatrol := TRUE;
  280.         WryteLn('Patrol aborted');
  281.         LEAVE;
  282.         END;
  283. END;
  284. {-------------------------------------------}
  285. PROCEDURE  AwaitKeypress;
  286. BEGIN
  287. WHILE TRUE DO
  288.   BEGIN
  289.   IF NOT(GetNextEvent(gEvtMask,gEvt)) THEN
  290.     CYCLE;
  291.   WITH gEvt DO
  292.     IF (what = keyDown) THEN
  293.       BEGIN
  294.       IF  (BAnd(modifiers,cmdKey)=cmdKey)
  295.       AND (BAnd(message,charCodeMask)=$2E)
  296.       THEN
  297.         BEGIN
  298.         gAbortPatrol := TRUE;
  299.         WryteLn('Patrol aborted');
  300.         END;
  301.       LEAVE;
  302.       END;
  303.   END;
  304. END;
  305. {-------------------------------------------}
  306. FUNCTION   Code0IsValid
  307.   :          BOOLEAN;
  308. BEGIN
  309. IF  gOption[eTrace] THEN
  310.   Trace('Code0IsValid');
  311. WITH TJTHdl(gCode0.fHdl)^^ DO
  312.   Code0IsValid := 
  313.     (gCode0.fSize     >= 24)    AND
  314.     (fAboveA5Size     >= 40)    AND
  315.     (fNbrBytesInTable >=  8)    AND
  316.     (fTableOffset     =  32)    AND
  317.     (fAboveA5Size = fNbrBytesInTable+32) AND
  318.     ((fNbrBytesInTable MOD 8) = 0);
  319. END;
  320. {-------------------------------------------}
  321. PROCEDURE  CommentBegins;
  322. BEGIN
  323. Wryte(gInd);
  324. Wryte(gInd);
  325. Wryte(gInd);
  326. END;
  327. {-------------------------------------------}
  328. PROCEDURE  CommentRsrcBegins
  329.   (pRsrcPtr: TRsrcPtr);
  330. BEGIN
  331. CommentBegins;
  332. WITH pRsrcPtr^ DO
  333.   BEGIN
  334.   WryteType(fResType);
  335.   WryteNbr (fResId,7);
  336.   Wryte    (' (');
  337.   ShortHexDump(Ptr(ORD4(@fResAttrs)+1),1);
  338.   WryteChar(')');
  339.   END;
  340. END;
  341. {-------------------------------------------}
  342. PROCEDURE  CountInfected;
  343. BEGIN
  344. IF  gOption[eTrace] THEN
  345.   Trace('CountInfected');
  346. INC(gCounts.fInfected);
  347. INC(gTotals.fInfected);
  348. END;
  349. {-------------------------------------------}
  350. PROCEDURE  DirectoryBegins;
  351. BEGIN
  352. IF  gOption[eTrace] THEN
  353.   Trace('DirectoryBegins');
  354. gReportFlags.fWroteDirname := FALSE;
  355. gScreenFlags.fWroteDirname := FALSE;
  356. END;
  357. {-------------------------------------------}
  358. PROCEDURE  DirectoryEnds;
  359. BEGIN
  360. IF  gOption[eTrace] THEN
  361.   Trace('DirectoryEnds');
  362. (*
  363. Wryte  ('End of ');
  364. WryteLn(gCurrDirname);
  365. *)
  366. END;
  367. {-------------------------------------------}
  368. FUNCTION   Disinfected_nVIR
  369.   :          BOOLEAN;
  370. VAR
  371.   snVIR2:    TRsrcRec;
  372.   sCodeGone: BOOLEAN;
  373. BEGIN
  374. IF  gOption[eTrace] THEN
  375.   Trace('Disinfected_nVIR');
  376. Disinfected_nVIR := FALSE;
  377. InitRsrc(@snVIR2);
  378. GetRsrc (@snVIR2,'nVIR',2,ResId);
  379. WITH snVIR2 DO
  380.   BEGIN
  381.   IF  (fFlag <> kRsrcHdlValid) THEN
  382.     BEGIN
  383.     ErrorInfected('No nVIR 2!');
  384.     ReleaseRsrc(@gCurrRsrc);
  385.     EXIT(Disinfected_nVIR);
  386.     END;
  387.   IF  (fSize < 8) THEN
  388.     BEGIN
  389.     ErrorInfected('Too small nVIR 2!');
  390.     ReleaseRsrc(@gCurrRsrc);
  391.     ReleaseRsrc(@snVIR2);
  392.     EXIT(Disinfected_nVIR);
  393.     END;
  394.   MoveHHi(fHdl);
  395.   HLock  (fHdl);
  396.   IF  NOT(FixedCode0(TJTEPtr(fHdl^))) THEN
  397.     BEGIN
  398.     ReleaseRsrc(@gCurrRsrc);
  399.     ReleaseRsrc(@snVIR2);
  400.     EXIT(Disinfected_nVIR);
  401.     END;
  402.   Disinfected_nVIR := TRUE;
  403.   sCodeGone := RemovedRsrc(@gCurrRsrc);
  404.   ReleaseRsrc(@snVIR2);
  405.   ProcessRsrcs('nVIR',@ProcessRemoveRsrc);
  406.   IF  sCodeGone 
  407.   AND (Count1Resources('nVIR') = 0) THEN
  408.     ErrorMsg('nVIR removed',0)
  409.   ELSE
  410.     BEGIN
  411.     ErrorMsg('nVIR “disinfected”:',0);
  412.     CommentBegins;
  413.     Wryte  ('All of its resources are now ');
  414.     Wryte  ('harmless, but some were not ');
  415.     WryteLn('removed, for some reason.');
  416.     END;
  417.   END;
  418. END;
  419. {-------------------------------------------}
  420. FUNCTION   Disinfected_Scores
  421.   :          BOOLEAN;
  422. BEGIN
  423. IF  gOption[eTrace] THEN
  424.   Trace('Disinfected_Scores');
  425. Disinfected_Scores := FALSE;
  426. WITH gCurrRsrc DO
  427.   BEGIN
  428.   MoveHHi(fHdl);
  429.   HLock  (fHdl);
  430.   WITH TScoresHdl(fHdl)^^ DO
  431.     IF  NOT(FixedCode0(@fOldJTE)) THEN
  432.       BEGIN
  433.       ReleaseRsrc(@gCurrRsrc);
  434.       EXIT(Disinfected_Scores);
  435.       END;
  436.   Disinfected_Scores := TRUE;
  437.   IF  RemovedRsrc(@gCurrRsrc) THEN
  438.     ErrorMsg('Scores removed',0)
  439.   ELSE
  440.     ErrorMsg('Scores disinfected',0);
  441.   END;
  442. END;
  443. {-------------------------------------------}
  444. PROCEDURE  ErrorBegins
  445.   (pStr:     Str255);
  446. BEGIN
  447. WryteFilename;
  448. Wryte  (gInd);
  449. Wryte  (gInd);
  450. Wryte  (pStr);
  451. END;
  452. {-------------------------------------------}
  453. PROCEDURE  ErrorEnds
  454.   (pBeeps:   INTEGER);
  455. VAR
  456.   i:         INTEGER;
  457.   sBeeps:    INTEGER;
  458. BEGIN
  459. IF  gOption[eBeeps] THEN
  460.   BEGIN
  461.   IF  (pBeeps > 4) THEN
  462.     sBeeps := 4
  463.   ELSE
  464.     sBeeps := pBeeps;
  465.   FOR i := 1 TO sBeeps DO
  466.     SysBeep(3);
  467.   END;
  468. IF  gOption[eAwait] THEN
  469.   BEGIN
  470.   WryteLn(' (WAITING ON KEY PRESS)');
  471.   AwaitKeypress;
  472.   END
  473. ELSE
  474.   WryteEoln;
  475. END;
  476. {-------------------------------------------}
  477. PROCEDURE  ErrorInfected
  478.   (pStr:     Str255);
  479. BEGIN
  480. IF  NOT(gInfectedWritten) THEN
  481.   BEGIN
  482.   ErrorBegins('**!INFECTED!** ');
  483.   WryteEoln;
  484.   gInfectedWritten := TRUE;
  485.   END;
  486. IF  (pStr <> '') THEN
  487.   BEGIN
  488.   CommentBegins;
  489.   Wryte(pStr);
  490.   ErrorEnds(3);
  491.   END;
  492. END;
  493. {-------------------------------------------}
  494. PROCEDURE  ErrorMsg
  495.   (pStr:     Str255;
  496.   pBeeps:    INTEGER);
  497. BEGIN
  498. ErrorBegins(pStr);
  499. ErrorEnds(pBeeps);
  500. END;
  501. {-------------------------------------------}
  502. PROCEDURE  ErrorOSErr
  503.   (pStr:     Str255);
  504. BEGIN
  505. IF  (pStr <> '') THEN
  506.   BEGIN
  507.   ErrorBegins(pStr);
  508.   WryteEoln;
  509.   END;
  510. CommentBegins;
  511. Wryte   ('OSErr code = ');
  512. WryteNbr(gError,1);
  513. ErrorEnds(2);
  514. END;
  515. {-------------------------------------------}
  516. FUNCTION   FixedCode0
  517.   (pJTPtr:   TJTEPtr)
  518.   :          BOOLEAN;
  519. BEGIN
  520. FixedCode0 := FALSE;
  521. IF  gOption[eTrace] THEN
  522.   Trace('FixedCode0');
  523. IF  NOT(JTEIsValid(pJTPtr)) THEN
  524.   BEGIN
  525.   ErrorInfected('Bad Jump Table Entry!');
  526.   EXIT(FixedCode0);
  527.   END;
  528. IF  NOT(gOption[eRmVir]) THEN
  529.   BEGIN
  530.   ErrorInfected('Remove option off');
  531.   CommentBegins;
  532.   WITH pJTPtr^ DO
  533.     BEGIN
  534.     Wryte   ('Jumps to ');
  535.     WryteNbr(fOffset,1);
  536.     Wryte   (' of CODE ');
  537.     WryteNbr(fSegId,1);
  538.     WryteEoln;
  539.     END;
  540.   ErrorMsg('Not removed',1);
  541.   EXIT(FixedCode0);
  542.   END;
  543. WITH gCode0 DO
  544.   BEGIN
  545.   IF  gOption[eTrace] THEN
  546.     BEGIN
  547.     Trace('About to restore CODE 0');
  548.     AbortPatrolIfCmdPeriodPressed;
  549.     IF  gAbortPatrol THEN
  550.       EXIT(FixedCode0);
  551.     END;
  552.   TJTHdl(fHdl)^^.fJTEntry[1] := pJTPtr^;
  553.   IF  (BAnd(fResAttrs,resProtected) <> 0)
  554.   AND (fResAttrs <> -1) THEN
  555.     BEGIN
  556.     SetResAttrs(fHdl,0);
  557.     ChangedResource(fHdl);
  558.     gError := ResError;
  559.     SetResAttrs(fHdl,fResAttrs);
  560.     END
  561.   ELSE
  562.     BEGIN
  563.     ChangedResource(fHdl);
  564.     gError := ResError;
  565.     END;
  566.   IF  (gError <> NoErr) THEN
  567.     BEGIN
  568.     ErrorInfected('CODE 0 unchanged!');
  569.     IF  (gError = wPrErr) THEN
  570.       ErrorMsg('Disk is locked',0)
  571.     ELSE
  572.       ErrorOSErr('');
  573.     gError := 0;
  574.     EXIT(FixedCode0);
  575.     END;
  576.   WriteResource(fHdl);
  577.   gError := ResError;
  578.   IF  (gError <> NoErr) THEN
  579.     BEGIN
  580.     ErrorInfected('CODE 0 unwritten!');
  581.     ErrorOSErr('');
  582.     EXIT(FixedCode0);
  583.     END;
  584.   END;
  585. FixedCode0 := TRUE;
  586. END;
  587. {-------------------------------------------}
  588. PROCEDURE  GetRsrc
  589.   (pRsrcPtr: TRsrcPtr;
  590.   pResType:  ResType;
  591.   pInt:      INTEGER;
  592.   pIntIs:    TResIdOrIndex);
  593. VAR
  594.   sName:     Str255;
  595.   sResLoad:  BOOLEAN;
  596.   {----------------------}
  597.   PROCEDURE  CommentWhich;
  598.   BEGIN
  599.   CommentBegins;
  600.   WryteType(pResType);
  601.   WryteChar(' ');
  602.   WryteNbr (pInt,1);
  603.   IF  (pIntIs = Index) THEN
  604.     Wryte  (' (indexed)');
  605.   WryteEoln;
  606.   END;
  607.   {----------------------}
  608. BEGIN
  609. WITH pRsrcPtr^ DO
  610.   BEGIN
  611.   IF  (fFlag <> kRsrcIsInitd) THEN
  612.     BEGIN
  613.     ErrorMsg('Logic error using GetRsrc',4);
  614.     AwaitKeypress;
  615.     ExitSecurityPatrol;
  616.     END;
  617.   fResType := pResType;
  618.   fResId   := pInt;
  619.   sResLoad := (TWordPtr(kResLoad)^ <> 0);
  620.   IF  (gActiveSelf OR gActiveSys) THEN
  621.     SetResLoad(FALSE);
  622.   IF  (pIntIs = Index) THEN
  623.     BEGIN
  624.     IF  gOption[eTrace] THEN
  625.       TraceRsrc('About to get ind',pRsrcPtr);
  626.     fHdl := Get1IndResource(pResType,pInt);
  627.     END
  628.   ELSE
  629.     BEGIN
  630.     IF  gOption[eTrace] THEN
  631.       TraceRsrc('About to get',pRsrcPtr);
  632.     fHdl := Get1Resource(pResType,pInt);
  633.     END;
  634.   IF  sResLoad THEN
  635.     BEGIN
  636.     IF  (gActiveSelf OR gActiveSys) THEN
  637.       SetResLoad(TRUE);
  638.     IF  (fHdl = NIL)
  639.     OR (ORD4(fHdl) = -1) THEN
  640.       BEGIN
  641.       gError := ResError;
  642.       ErrorOSErr('Couldn’t get resource');
  643.       CommentWhich;
  644.       InitRsrc(pRsrcPtr);
  645.       EXIT(GetRsrc);
  646.       END;
  647.     fFlag := kRsrcHdlValid;
  648.     fResAttrs := GetResAttrs(fHdl);
  649.     IF  (ResError <> NoErr) THEN
  650.       fResAttrs := -1;
  651.     IF  (fHdl^ = NIL) THEN
  652.       BEGIN
  653.       LoadResource(fHdl);
  654.       fLoaded := eWeLoadedIt;
  655.       IF  gOption[eTrace] THEN
  656.         Trace('We loaded it');
  657.       END
  658.     ELSE
  659.       BEGIN
  660.       fLoaded := eAlreadyLoaded;
  661.       IF  gOption[eTrace] THEN
  662.         Trace('Already loaded');
  663.       END;
  664.     IF  (fHdl^ = NIL) THEN
  665.       BEGIN
  666.       gError := ResError;
  667.       IF  (gError <> NoErr) THEN
  668.         BEGIN
  669.         ErrorMsg('Couldn’t load resource',0);
  670.         IF  (gError = memFullErr) THEN
  671.           ErrorMsg('No room in heap zone',1)
  672.         ELSE
  673.           ErrorOSErr('');
  674.         CommentWhich;
  675.         ReleaseRsrc(pRsrcPtr);
  676.         EXIT(GetRsrc);
  677.         END;
  678.       END;
  679.     fSize := SizeResource(fHdl);
  680.     END
  681.   ELSE
  682.     BEGIN
  683.     fFlag   := kRsrcHdlValid;
  684.     fSize   := MaxSizeRsrc(fHdl);
  685.     fLoaded := eNotYet;
  686.     IF  gOption[eTrace] THEN
  687.       Trace('No-load get, loaded not yet');
  688.     END;
  689.   IF  (pIntIs = Index) THEN
  690.     BEGIN
  691.     GetResInfo(fHdl,fResId,fResType,sName);
  692.     gError := ResError;
  693.     IF  (gError <> NoErr) THEN
  694.       BEGIN
  695.       ErrorOSErr('Couldn’t get resource id');
  696.       CommentWhich;
  697.       ReleaseRsrc(pRsrcPtr);
  698.       EXIT(GetRsrc);
  699.       END;
  700.     END;
  701.   IF  sResLoad THEN
  702.     BEGIN
  703.     fState := HGetState(fHdl);
  704.     IF ((fResType = 'CODE')
  705.     AND (fResId   = 0)) THEN
  706.       BEGIN
  707.       MoveHHi(fHdl);
  708.       HLock  (fHdl);
  709.       END
  710.     ELSE
  711.       HNoPurge(fHdl);
  712.     END;
  713.   END;
  714. IF  gOption[eTrace] THEN
  715.   TraceRsrc('Got',pRsrcPtr);
  716. INC(gCounts.fResources);
  717. INC(gTotals.fResources);
  718. END;
  719. {-------------------------------------------}
  720. PROCEDURE  InitGlobals;
  721. VAR
  722.   sGetHdl:   DialogTHndl;
  723.   sGetSize:  Point;
  724.   sPutHdl:   DialogTHndl;
  725.   sPutSize:  Point;
  726.   sScrnSize: Point;
  727. BEGIN
  728. ZeroOutRange(@gAAGlobals,@gZZGlobals);
  729. gCurrIOBuffer := NewPtr(kIOBufferSize);
  730. InitRsrc(@gCode0);
  731. InitRsrc(@gCurrRsrc);
  732. gEvtMask := 
  733.   everyEvent - (updateMask + activMask);
  734. GetPort(gGrafPtr);
  735. gInd      := '    ';
  736.  
  737. sGetHdl := 
  738.   DialogTHndl(GetResource('DLOG',getDlgID));
  739. IF  (sGetHdl = NIL)
  740. OR  (LONGINT(sGetHdl) = -1) THEN
  741.   SetPt(sGetSize,304,104)
  742. ELSE
  743.   BEGIN
  744.   IF  (sGetHdl^ = NIL) THEN
  745.     LoadResource(Handle(sGetHdl));
  746.   sGetSize := sGetHdl^^.boundsRect.botRight;
  747.   ReleaseResource(Handle(sGetHdl));
  748.   END;
  749.  
  750. sPutHdl := 
  751.   DialogTHndl(GetResource('DLOG',putDlgID));
  752. IF  (sPutHdl = NIL)
  753. OR  (LONGINT(sPutHdl) = -1) THEN
  754.   SetPt(sPutSize,348,136)
  755. ELSE
  756.   BEGIN
  757.   IF  (sPutHdl^ = NIL) THEN
  758.     LoadResource(Handle(sPutHdl));
  759.   sPutSize := sPutHdl^^.boundsRect.botRight;
  760.   ReleaseResource(Handle(sPutHdl));
  761.   END;
  762.  
  763. WITH gGrafPtr^.portBits.bounds DO
  764.   BEGIN
  765.   sScrnSize.h := right-left;
  766.   sScrnSize.v := bottom-top;
  767.   END;
  768. gSFGetPt.h := (sScrnSize.h-sGetSize.h) DIV 2;
  769. gSFGetPt.v := (sScrnSize.v-sGetSize.v) DIV 2;
  770. gSFPutPt.h := (sScrnSize.h-sPutSize.h) DIV 2;
  771. gSFPutPt.v := (sScrnSize.v-sPutSize.v) DIV 2;
  772. END;
  773. {-------------------------------------------}
  774. PROCEDURE  InitRsrc
  775.   (pRsrcPtr: TRsrcPtr);
  776. BEGIN
  777. ZeroOut(Ptr(pRsrcPtr),SIZEOF(TRsrcRec));
  778. pRsrcPtr^.fFlag := kRsrcIsInitd;
  779. END;
  780. {-------------------------------------------}
  781. FUNCTION   JTEIsValid
  782.   (pJTEPtr:  TJTEPtr)
  783.   :          BOOLEAN;
  784. VAR
  785.   sCode:     TRsrcRec;
  786. BEGIN
  787. IF  gOption[eTrace] THEN
  788.   Trace('JTEIsValid');
  789. JTEIsValid := FALSE;
  790. WITH pJTEPtr^, sCode DO
  791.   BEGIN
  792.   InitRsrc(@sCode);
  793.   SetResLoad(FALSE);
  794.   GetRsrc(@sCode,'CODE',fSegId,ResId);
  795.   SetResLoad(TRUE);
  796.   IF  (fFlag <> kRsrcHdlValid) THEN
  797.     EXIT(JTEIsValid);
  798.   JTEIsValid := 
  799.     (fSkip3F3C  = $3F3C)  AND
  800.     (fSegId     > 0)      AND
  801.     (fSkipA9F0  = -22032) AND  { $A9F0 }
  802.     (fSize      > 0);
  803.   ReleaseRsrc(@sCode);
  804.   END;
  805. END;
  806. {-------------------------------------------}
  807. PROCEDURE  ListCounts
  808.   (pPtr:     TCountsPtr);
  809. BEGIN
  810. IF  gOption[eTrace] THEN
  811.   Trace('CountsListing');
  812. WITH pPtr^ DO
  813.   BEGIN
  814.   WryteLn ('Files:');
  815.   WryteNbr(fFiles,    6);
  816.   WryteLn (' processed');
  817.   WryteNbr(fExamined,6);
  818.   WryteLn (' examined');
  819.   WryteNbr(fDeleted,  6);
  820.   WryteLn (' deleted');
  821.   WryteLn ('Resources:');
  822.   WryteNbr(fResources,6);
  823.   WryteLn (' processed');
  824.   WryteNbr(fInfected, 6);
  825.   WryteLn (' infected');
  826.   WryteNbr(fRemoved,  6);
  827.   WryteLn (' removed');
  828.   Wryte   ('Currently available memory is ');
  829.   WryteNbr(MemAvail DIV 1024,1);
  830.   WryteLn ('K.');
  831.   PauseBriefly;
  832.   END;
  833. END;
  834. {-------------------------------------------}
  835. PROCEDURE  LookForKnownViruses;
  836. VAR
  837.   sWeUsedToBeInfected: BOOLEAN;
  838.   {--------------------}
  839.   PROCEDURE  Get1stCode;
  840.   BEGIN
  841.   WITH TJTHdl(gCode0.fHdl)^^.fJTEntry[1] DO
  842.     BEGIN
  843.     GetRsrc(@gCurrRsrc,'CODE',fSegId,ResId);
  844.     IF  (gCurrRsrc.fFlag<>kRsrcHdlValid) THEN
  845.       BEGIN
  846.       ErrorInfected('Couldn’t get 1st CODE');
  847.       InitRsrc(@gCurrRsrc);
  848.       EXIT(LookForKnownViruses);
  849.       END;
  850.     END;
  851.   END;
  852.   {--------------------}
  853. BEGIN
  854. IF  gOption[eTrace] THEN
  855.   Trace('LookForKnownViruses');
  856. sWeUsedToBeInfected := FALSE;
  857. Get1stCode;
  858. WITH gCurrRsrc DO
  859.   BEGIN
  860.   LookForVirus_nVIR;
  861.   IF  fInfected THEN
  862.     BEGIN
  863.     CountInfected;
  864.     IF  fKnown AND (fSize = 372) THEN
  865.       ErrorInfected('nVIR 372 virus')
  866.     ELSE IF fKnown AND (fSize = 422) THEN
  867.       ErrorInfected('nVIR 422 virus')
  868.     ELSE
  869.       BEGIN
  870.       ErrorInfected('New nVIR virus!');
  871.       gFgPrTitle := '';
  872.       CommentFgPrRsrc(@gCurrRsrc);
  873.       END;
  874.     IF  Disinfected_nVIR THEN
  875.       sWeUsedToBeInfected := TRUE;
  876.     Get1stCode;
  877.     END;
  878.   LookForVirus_Scores;
  879.   IF  fKnown AND fInfected THEN
  880.     BEGIN
  881.     CountInfected;
  882.     ErrorInfected('Scores virus');
  883.     IF  Disinfected_Scores THEN
  884.       sWeUsedToBeInfected := TRUE;
  885.     END
  886.   ELSE
  887.     ReleaseRsrc(@gCurrRsrc);
  888.   END;
  889. IF  sWeUsedToBeInfected THEN
  890.   LookForKnownViruses;
  891. END;
  892. {-------------------------------------------}
  893. PROCEDURE  PatrolBegins;
  894. BEGIN
  895. IF  gOption[eTrace] THEN
  896.   Trace('PatrolBegins');
  897. WryteEoln;
  898. WryteLn('*******************************');
  899. ZeroOut(@gCounts,SIZEOF(TCountsRec));
  900. GetDateTime(gSecsBegins);
  901. END;
  902. {-------------------------------------------}
  903. PROCEDURE  PatrolEnds;
  904. VAR
  905.   sMins:     INTEGER;
  906.   sSecs:     INTEGER;
  907. BEGIN
  908. GetDateTime(gSecsEnds);
  909. sSecs := gSecsEnds - gSecsBegins;
  910. sMins := sSecs DIV 60;
  911. sSecs := sSecs - (sMins * 60);
  912. WryteEoln;
  913. WryteLn('*******************************');
  914. WryteEoln;
  915. Wryte   ('End of patrol that took ');
  916. WryteNbr(sMins,1);
  917. WryteChar(':');
  918. IF  (sSecs < 10) THEN
  919.   BEGIN
  920.   WryteChar('0');
  921.   WryteNbr (sSecs,1);
  922.   END
  923. ELSE
  924.   WryteNbr (sSecs,2);
  925. WryteEoln;
  926. ListCounts(@gCounts);
  927. END;
  928. {-------------------------------------------}
  929. PROCEDURE  PauseBriefly;
  930. VAR
  931.   sTicks:    LONGINT;
  932. BEGIN
  933. Delay(120,sTicks);
  934. END;
  935. {-------------------------------------------}
  936. PROCEDURE  ProcessCodes;
  937. VAR
  938.   i:           INTEGER;
  939.   sNbrEntries: INTEGER;
  940.   sPrevId:     INTEGER;
  941.   sWeirdCode0: BOOLEAN;
  942.   {------------------------}
  943.   PROCEDURE    CommentWhere;
  944.   BEGIN
  945.   CommentBegins;
  946.   Wryte   ('At entry ');
  947.   WryteNbr(i,1);
  948.   WryteEoln;
  949.   END;
  950.   {------------------------}
  951. BEGIN
  952. IF  gOption[eTrace] THEN
  953.   Trace('ProcessCodes');
  954. GetRsrc(@gCode0,'CODE',0,ResId);
  955. IF  (gCode0.fFlag <> kRsrcHdlValid) THEN
  956.   BEGIN
  957.   ErrorMsg('Code rsrcs without CODE 0',1);
  958.   EXIT(ProcessCodes);
  959.   END;
  960. IF  NOT(Code0IsValid) THEN
  961.   BEGIN
  962.   ErrorMsg('Unexpected CODE 0 values',1);
  963.   ReleaseRsrc(@gCode0);
  964.   EXIT(ProcessCodes);
  965.   END;
  966. LookForKnownViruses;
  967. WITH TJTHdl(gCode0.fHdl)^^ DO
  968.   BEGIN
  969.   sNbrEntries := fNbrBytesInTable DIV 8;
  970.   sPrevId     := 1;
  971.   sWeirdCode0 := 
  972.     (COPY(gCurrFilename,1,9)='Red Ryder') OR
  973.     (COPY(gCurrFilename,1,6)='Canvas'   ) OR
  974.     (COPY(gCurrFilename,1,9)='PageMaker');
  975.   FOR i := 1 TO sNbrEntries DO
  976.     WITH fJTEntry[i] DO
  977.       BEGIN
  978.       IF  (fSkip3F3C  = $3F3C)
  979.       AND (fSegId     = sPrevId)
  980.       AND (fSkipA9F0  = -22032) THEN
  981.         CYCLE;
  982.       AbortPatrolIfCmdPeriodPressed;
  983.       IF  gAbortPatrol THEN
  984.         LEAVE;
  985.       IF  NOT(JTEIsValid(@fJTEntry[i])) THEN
  986.         BEGIN
  987.         ErrorMsg('CODE 0 has invalid JTE',1);
  988.         CommentWhere;
  989.         LEAVE;
  990.         END;
  991.       IF  sWeirdCode0 THEN
  992.         BEGIN
  993.         sPrevId := fSegId;
  994.         CYCLE;
  995.         END;
  996.       IF  (fSegId < sPrevId) THEN
  997.         BEGIN
  998.         ErrorMsg('JT not ascending',1);
  999.         CommentWhere;
  1000.         LEAVE;
  1001.         END;
  1002.       INC(sPrevId);
  1003.       IF  (fSegId = sPrevId) THEN
  1004.         CYCLE;
  1005.       ErrorMsg('JT skips ResId',1);
  1006.       CommentWhere;
  1007.       LEAVE;
  1008.       END;
  1009.   END;
  1010. ReleaseRsrc(@gCode0);
  1011. END;
  1012. {-------------------------------------------}
  1013. PROCEDURE  ProcessFile;
  1014. VAR
  1015.   sSaveC1T:  INTEGER;
  1016.   {----------------------------}
  1017.   PROCEDURE  ExitIfCantReadFork;
  1018.   BEGIN
  1019.   IF  (gError <> NoErr) THEN
  1020.     BEGIN
  1021.     IF  (gError = eofErr) THEN
  1022.       { no resource fork }
  1023.     ELSE IF  (gError = fnfErr) THEN
  1024.       ErrorMsg('File not found',1)
  1025.     ELSE IF  (gError = nsvErr) THEN
  1026.       ErrorMsg('No such volume',1)
  1027.     ELSE IF  (gError = opWrErr) THEN
  1028.       ErrorMsg(CONCAT('Already in use.  ',
  1029.         '(Don’t use under MultiFinder!)'),1)
  1030.     ELSE
  1031.       ErrorOSErr('Couldn’t open file');
  1032.     gError := NoErr;
  1033.     EXIT(ProcessFile);
  1034.     END;
  1035.   END;
  1036.   {----------------------------}
  1037. BEGIN
  1038. IF  gOption[eTrace] THEN
  1039.   Trace('ProcessFile');
  1040. AbortPatrolIfCmdPeriodPressed;
  1041. IF  gAbortPatrol THEN
  1042.   EXIT(ProcessFile);
  1043. INC(gCounts.fFiles);
  1044. INC(gTotals.fFiles);
  1045. gInfected                   := FALSE;
  1046. gInfectedWritten            := FALSE;
  1047. gReportFlags.fWroteFilename := FALSE;
  1048. gScreenFlags.fWroteFilename := FALSE;
  1049. IF  gOption[eLList] THEN
  1050.   WryteFilename
  1051. ELSE
  1052.   WryteFilenameToScreenOnlyForNow;
  1053. IF  (LENGTH(gCurrFilename) > 0) THEN
  1054.   IF (gCurrFilename[1] = '.') THEN
  1055.     BEGIN
  1056.     ErrorMsg('Filename begins with “.”',1);
  1057.     EXIT(ProcessFile);
  1058.     END;
  1059. IF  gActiveSelf AND NOT(kProcessSelf) THEN
  1060.   EXIT(ProcessFile);
  1061. gCurrEOF := -1;
  1062. gError := FSOpen(gCurrFilename,gCurrWDRefNum,
  1063.                  gCurrRefNum);
  1064. ExitIfCantReadFork;
  1065. gError := GetEOF(gCurrRefNum,gCurrEOF);
  1066. IF  (gError = NoErr) THEN
  1067.   BEGIN
  1068.   WITH gCurrFInfo DO
  1069.     IF  (COPY(gCurrFilename,1,7)='MacsBug') 
  1070.     OR  (fdType = 'RELB') 
  1071.     OR  (fdType = 'OBJ ') THEN
  1072.       IF  NOT(KnownDataFork) THEN
  1073.         CommentFgPrData;
  1074.   gError := FSClose(gCurrRefNum);
  1075.   IF  (gError <> NoErr) THEN
  1076.     ErrorOSErr('Couldn’t close data fork');
  1077.   END
  1078. ELSE
  1079.   ErrorOSErr('Couldn’t GetEOF');
  1080. IF  gActiveSelf THEN
  1081.   BEGIN
  1082.   gCurrRefNum := TWordPtr(kCurApRefNum)^;
  1083.   gError  := NoErr;
  1084.   END
  1085. ELSE IF  gActiveSys THEN
  1086.   BEGIN
  1087.   gCurrRefNum := TWordPtr(kSysMap)^;
  1088.   gError  := NoErr;
  1089.   END
  1090. ELSE
  1091.   BEGIN
  1092.   SetResLoad(FALSE);
  1093.   gCurrRefNum := OpenRFPerm(gCurrFilename,
  1094.                             gCurrWDRefNum,
  1095.                             fsRdWrPerm);
  1096.   gError  := ResError;
  1097.   SetResLoad(TRUE);
  1098.   ExitIfCantReadFork;
  1099.   END;
  1100. IF  (gCurrRefNum <> CurResFile) THEN
  1101.   BEGIN
  1102.   UseResFile(gCurrRefNum);
  1103.   gError := ResError;
  1104.   IF  (gError <> NoErr) THEN
  1105.     BEGIN
  1106.     ErrorOSErr('Couldn’t use resource fork');
  1107.     gError := NoErr; 
  1108.     EXIT(ProcessFile);
  1109.     END;
  1110.   END;
  1111. INC(gCounts.fExamined);
  1112. INC(gTotals.fExamined);
  1113. IF  (Count1Resources('CODE') > 0) THEN
  1114.   ProcessCodes;
  1115. gFgPrTitle := 'Unknown Resource(s):';
  1116. ProcessRsrcs('ADBS',@Process_ADBS);
  1117. ProcessRsrcs('CACH',@Process_CACH);
  1118. ProcessRsrcs('CDEF',@Process_CDEF);
  1119. ProcessRsrcs('DATA',@Process_DATA);
  1120. ProcessRsrcs('DRVR',@Process_DRVR);
  1121. ProcessRsrcs('DSAT',@Process_DSAT);
  1122. ProcessRsrcs('FKEY',@Process_FKEY);
  1123. ProcessRsrcs('FMTR',@Process_FMTR);
  1124. ProcessRsrcs('INIT',@Process_INIT);
  1125. ProcessRsrcs('LDEF',@Process_LDEF);
  1126. ProcessRsrcs('MBDF',@Process_MBDF);
  1127. ProcessRsrcs('MDEF',@Process_MDEF);
  1128. ProcessRsrcs('MMAP',@Process_MMAP);
  1129. ProcessRsrcs('NBPC',@Process_NBPC);
  1130. ProcessRsrcs('PACK',@Process_PACK);
  1131. ProcessRsrcs('PDEF',@Process_PDEF);
  1132. ProcessRsrcs('PTCH',@Process_PTCH);
  1133. ProcessRsrcs('ROv#',@Process_ROvList);
  1134. ProcessRsrcs('ROvr',@Process_ROvr);
  1135. ProcessRsrcs('SERD',@Process_SERD);
  1136. ProcessRsrcs('WDEF',@Process_WDEF);
  1137. ProcessRsrcs('XCMD',@Process_XCMD);
  1138. ProcessRsrcs('XFCN',@Process_XFCN);
  1139. ProcessRsrcs('atpl',@Process_atpl);
  1140. ProcessRsrcs('boot',@Process_boot);
  1141. ProcessRsrcs('cdev',@Process_cdev);
  1142. ProcessRsrcs('mppc',@Process_mppc);
  1143. ProcessRsrcs('snth',@Process_snth);
  1144. ProcessRsrcs('view',@Process_view);
  1145. IF  gOption[eFgPr] THEN
  1146.   BEGIN
  1147.   gFgPrTitle := 'Fingerprint(s):';
  1148.   ProcessRsrcs('ADBS',@ProcessCurrRsrc);
  1149.   ProcessRsrcs('CACH',@ProcessCurrRsrc);
  1150.   ProcessRsrcs('CDEF',@ProcessCurrRsrc);
  1151.   IF  gOption[eFgPrC] THEN
  1152.     ProcessRsrcs('CODE',@ProcessCurrRsrc);
  1153.   ProcessRsrcs('DATA',@ProcessCurrRsrc);
  1154.   ProcessRsrcs('DRVR',@ProcessCurrRsrc);
  1155.   ProcessRsrcs('DSAT',@ProcessCurrRsrc);
  1156.   ProcessRsrcs('FKEY',@ProcessCurrRsrc);
  1157.   ProcessRsrcs('FMTR',@ProcessCurrRsrc);
  1158.   ProcessRsrcs('INIT',@ProcessCurrRsrc);
  1159.   ProcessRsrcs('LDEF',@ProcessCurrRsrc);
  1160.   ProcessRsrcs('MBDF',@ProcessCurrRsrc);
  1161.   ProcessRsrcs('MDEF',@ProcessCurrRsrc);
  1162.   ProcessRsrcs('MMAP',@ProcessCurrRsrc);
  1163.   ProcessRsrcs('NBPC',@ProcessCurrRsrc);
  1164.   ProcessRsrcs('PACK',@ProcessCurrRsrc);
  1165.   ProcessRsrcs('PDEF',@ProcessCurrRsrc);
  1166.   ProcessRsrcs('PTCH',@ProcessCurrRsrc);
  1167.   ProcessRsrcs('ROv#',@ProcessCurrRsrc);
  1168.   ProcessRsrcs('ROvr',@ProcessCurrRsrc);
  1169.   ProcessRsrcs('SERD',@ProcessCurrRsrc);
  1170.   ProcessRsrcs('WDEF',@ProcessCurrRsrc);
  1171.   ProcessRsrcs('XCMD',@ProcessCurrRsrc);
  1172.   ProcessRsrcs('XFCN',@ProcessCurrRsrc);
  1173.   ProcessRsrcs('atpl',@ProcessCurrRsrc);
  1174.   ProcessRsrcs('boot',@ProcessCurrRsrc);
  1175.   ProcessRsrcs('cdev',@ProcessCurrRsrc);
  1176.   ProcessRsrcs('mppc',@ProcessCurrRsrc);
  1177.   ProcessRsrcs('snth',@ProcessCurrRsrc);
  1178.   ProcessRsrcs('view',@ProcessCurrRsrc);
  1179.   ProcessRsrcs('nVIR',@ProcessCurrRsrc);
  1180.   END;
  1181. IF  gActiveSelf OR gActiveSys THEN
  1182.   EXIT(ProcessFile);
  1183. sSaveC1T := Count1Types;
  1184. CloseResFile(gCurrRefNum);
  1185. IF  NOT(gInfected) THEN
  1186.   EXIT(ProcessFile);
  1187. WITH gCurrFInfo DO
  1188.   BEGIN
  1189.   IF ((gCurrFilename = 'Note Pad File')
  1190.   OR  (gCurrFilename = 'Scrapbook File'))
  1191.   AND (fdCreator = 'ZSYS')
  1192.   AND gOption[eRmVir] THEN
  1193.     BEGIN
  1194.     fdType    := 'ZSYS';
  1195.     fdCreator := 'MACS';
  1196.     fdFlags   := 4096;
  1197.     gError    := SetFInfo(gCurrFilename,
  1198.                           gCurrWDRefNum,
  1199.                           gCurrFInfo);
  1200.     IF  (gError = NoErr) THEN
  1201.       ErrorMsg('Reset to system document',0)
  1202.     ELSE
  1203.       ErrorOSErr('FInfo not reset');
  1204.     EXIT(ProcessFile);
  1205.     END;
  1206.   END;
  1207. IF  (gCurrEOF <> 0) THEN
  1208.   BEGIN
  1209.   ErrorMsg('File still has data fork',0);
  1210.   ErrorMsg('File not deleted',1);
  1211.   EXIT(ProcessFile);
  1212.   END;
  1213. IF  (sSaveC1T <> 0) THEN
  1214.   BEGIN
  1215.   ErrorMsg('File still has resources',0);
  1216.   ErrorMsg('File not deleted',1);
  1217.   EXIT(ProcessFile);
  1218.   END;
  1219. ErrorMsg('File emptied',0);
  1220. gError := 
  1221.   FSDelete(gCurrFilename,gCurrWDRefNum);
  1222. IF  (gError = NoErr) THEN
  1223.   BEGIN
  1224.   gCurrFileDeleted := TRUE;
  1225.   INC(gCounts.fDeleted);
  1226.   INC(gTotals.fDeleted);
  1227.   ErrorMsg('File deleted',1);
  1228.   END
  1229. ELSE
  1230.   ErrorOSErr('File not deleted');
  1231. END;
  1232. {-------------------------------------------}
  1233. PROCEDURE  ProcessRsrcs
  1234.   (pResType: ResType;
  1235.   pProcPtr:  ProcPtr);
  1236. VAR
  1237.   i:         INTEGER;
  1238.   sIdx:      INTEGER;
  1239. BEGIN
  1240. IF  gOption[eTrace] THEN
  1241.   Trace('ProcessRsrcs');
  1242. WITH gCurrRsrc DO
  1243.   BEGIN
  1244.   sIdx := 1;
  1245.   FOR i := 1 TO Count1Resources(pResType) DO
  1246.     BEGIN
  1247.     AbortPatrolIfCmdPeriodPressed;
  1248.     IF  gAbortPatrol THEN
  1249.       LEAVE;
  1250.     GetRsrc(@gCurrRsrc,pResType,sIdx,Index);
  1251.     IF  (fFlag <> kRsrcHdlValid) THEN
  1252.       BEGIN
  1253.       INC(sIdx);
  1254.       CYCLE;
  1255.       END;
  1256.     CallProcPtr(pProcPtr);
  1257.     IF  fInfected THEN
  1258.       BEGIN
  1259.       CountInfected;
  1260.       ErrorInfected('');
  1261.       CommentRsrcBegins(@gCurrRsrc);
  1262.       WryteLn(' is an infection');
  1263.       IF  RemovedRsrc(@gCurrRsrc) THEN
  1264.         BEGIN
  1265.         ErrorMsg('Removed',0);
  1266.         CYCLE;
  1267.         END;
  1268.       ErrorMsg('Not removed',1);
  1269.       INC(sIdx);
  1270.       CYCLE;
  1271.       END;
  1272.     IF  NOT(fKnown) THEN
  1273.       CommentFgPrRsrc(@gCurrRsrc);
  1274.     ReleaseRsrc(@gCurrRsrc);
  1275.     INC(sIdx);
  1276.     END;
  1277.   END;
  1278. END;
  1279. {-------------------------------------------}
  1280. PROCEDURE  ReleaseRsrc
  1281.   (pRsrcPtr: TRsrcPtr);
  1282. BEGIN
  1283. WITH pRsrcPtr^ DO
  1284.   BEGIN
  1285.   IF  (fFlag <> kRsrcHdlValid) THEN
  1286.     BEGIN
  1287.     ErrorMsg('Error using ReleaseRsrc',4);
  1288.     AwaitKeypress;
  1289.     ExitSecurityPatrol;
  1290.     END;
  1291.   IF  gOption[eTrace] THEN
  1292.     TraceRsrc('About to release',pRsrcPtr);
  1293.   IF  (gActiveSelf OR gActiveSys) THEN
  1294.     IF  gOption[eTrace] THEN
  1295.       Trace('Not Released')
  1296.     ELSE
  1297.   ELSE
  1298.     BEGIN
  1299.     HSetState(fHdl,fState);
  1300.     ReleaseResource(fHdl);
  1301.     IF  gOption[eTrace] THEN
  1302.       Trace('Released');
  1303.     END;
  1304.   InitRsrc(pRsrcPtr);
  1305.   END;
  1306. END;
  1307. {-------------------------------------------}
  1308. FUNCTION   RemovedRsrc
  1309.   (pRsrcPtr: TRsrcPtr)
  1310.   :          BOOLEAN;
  1311. VAR
  1312.   sBits0and7:LONGINT;
  1313.   {--------------------}
  1314.   PROCEDURE  ExitIfError
  1315.     (pStr:     Str255);
  1316.   BEGIN
  1317.   gError := ResError;
  1318.   IF  (gError <> NoErr) THEN
  1319.     BEGIN
  1320.     ErrorMsg(pStr,0);
  1321.     IF  (gError = wPrErr) THEN
  1322.       ErrorMsg('Disk is locked',0)
  1323.     ELSE
  1324.       ErrorOSErr('');
  1325.     CommentRsrcBegins(pRsrcPtr);
  1326.     WryteLn(' not removed');
  1327.     ReleaseRsrc(pRsrcPtr);
  1328.     EXIT(RemovedRsrc);
  1329.     END;
  1330.   END;
  1331.   {--------------------}
  1332. BEGIN
  1333. RemovedRsrc := FALSE;
  1334. IF  gOption[eTrace] THEN
  1335.   Trace('RemovedRsrc');
  1336. AbortPatrolIfCmdPeriodPressed;
  1337. IF  gAbortPatrol
  1338. OR  NOT(gOption[eRmVir]) THEN
  1339.   BEGIN
  1340.   ReleaseRsrc(pRsrcPtr);
  1341.   EXIT(RemovedRsrc);
  1342.   END;
  1343. WITH pRsrcPtr^ DO
  1344.   BEGIN
  1345.   IF  (fFlag <> kRsrcHdlValid) THEN
  1346.     BEGIN
  1347.     ErrorMsg('Error using RemovedRsrc',4);
  1348.     AwaitKeypress;
  1349.     ExitSecurityPatrol;
  1350.     END;
  1351.   IF  gOption[eTrace] THEN
  1352.     BEGIN
  1353.     TraceRsrc('About to remove',pRsrcPtr);
  1354.     AbortPatrolIfCmdPeriodPressed;
  1355.     IF  gAbortPatrol THEN
  1356.       EXIT(RemovedRsrc);
  1357.     END;
  1358.   IF  NOT(fInfected) THEN
  1359.     BEGIN
  1360.     ErrorMsg('Tried to remove uninfected',4);
  1361.     AwaitKeypress;
  1362.     ExitSecurityPatrol;
  1363.     END;
  1364.   IF  kZeroOutVirs AND (fHdl^ <> NIL) THEN
  1365.     BEGIN
  1366.     ZeroOut(fHdl^,fSize);
  1367.     ChangedResource(fHdl);
  1368.     gError := ResError;
  1369.     IF  (gError = NoErr) THEN
  1370.       BEGIN
  1371.       WriteResource(fHdl);
  1372.       gError := ResError;
  1373.       IF  (gError <> NoErr) THEN
  1374.         ErrorOSErr('Couldn’t WriteResource');
  1375.       END
  1376.     ELSE
  1377.       ErrorOSErr('Couldn’t ChangedResource');
  1378.     END;
  1379.   sBits0and7 := BAnd(fResAttrs,$81);
  1380.   SetResAttrs(fHdl,LoWord(sBits0and7));
  1381.   RmveResource(fHdl);
  1382.   ExitIfError('Couldn’t remove resource');
  1383.   UpdateResFile(gCurrRefNum);
  1384.   ExitIfError('Couldn’t update res file');
  1385.   DisposHandle(fHdl);
  1386.   InitRsrc(pRsrcPtr);
  1387.   RemovedRsrc := TRUE;
  1388.   IF  gOption[eTrace] THEN
  1389.     Trace('RemovedRsrc successful');
  1390.   END;
  1391. INC(gCounts.fRemoved);
  1392. INC(gTotals.fRemoved);
  1393. END;
  1394. {-------------------------------------------}
  1395. PROCEDURE  ShortHexDump
  1396.   (pPtr:     Ptr;
  1397.   pNbrBytes: SignedByte);
  1398. VAR
  1399.   i:         INTEGER;
  1400.   sCh1,sCh2: LONGINT;
  1401.   sDigit:    LONGINT;
  1402.   sIdx:      Ptr;
  1403. BEGIN
  1404. sIdx  := pPtr;
  1405. FOR i := 1 TO pNbrBytes DO
  1406.   BEGIN
  1407.   sDigit := ORD4(sIdx^);
  1408.   sCh1   := BSR(BAnd(sDigit,$F0),4);
  1409.   sCh2   :=     BAnd(sDigit,$0F);
  1410.   IF  sCh1 > 9 THEN
  1411.     WryteChar(CHR(sCh1 + $37))
  1412.   ELSE
  1413.     WryteChar(CHR(sCh1 + $30));
  1414.   IF  sCh2 > 9 THEN
  1415.     WryteChar(CHR(sCh2 + $37))
  1416.   ELSE
  1417.     WryteChar(CHR(sCh2 + $30));
  1418.   INC(LONGINT(sIdx));
  1419.   END;
  1420. END;
  1421. {-------------------------------------------}
  1422. PROCEDURE  Trace
  1423.   (pStr:     Str255);
  1424. BEGIN
  1425. ErrorBegins(pStr);
  1426. ErrorEnds(0);
  1427. END;
  1428. {-------------------------------------------}
  1429. PROCEDURE  TraceNbr
  1430.   (pStr:     Str255;
  1431.   pNbr:      LONGINT);
  1432. BEGIN
  1433. ErrorBegins(pStr);
  1434. WryteNbr(pNbr,1);
  1435. ErrorEnds(0);
  1436. END;
  1437. {-------------------------------------------}
  1438. PROCEDURE  TraceRsrc
  1439.   (pStr:     Str255;
  1440.   pRsrcPtr:  TRsrcPtr);
  1441. BEGIN
  1442. ErrorBegins(pStr);
  1443. WITH pRsrcPtr^ DO
  1444.   BEGIN
  1445.   WryteChar(' ');
  1446.   WryteType(fResType);
  1447.   WryteNbr (fResId,7);
  1448.   END;
  1449. ErrorEnds(0);
  1450. END;
  1451. {-------------------------------------------}
  1452. PROCEDURE  ZeroOut
  1453.   (pStart:   Ptr;
  1454.   pCount:    Size);
  1455. VAR
  1456.   i:         INTEGER;
  1457.   sIdx:      Ptr;
  1458. BEGIN
  1459. sIdx := pStart;
  1460. FOR i := 1 TO pCount DO
  1461.   BEGIN
  1462.   sIdx^ := 0;
  1463.   INC(LONGINT(sIdx));
  1464.   END;
  1465. END;
  1466. {-------------------------------------------}
  1467. PROCEDURE  ZeroOutRange
  1468.   (p1:       Ptr;
  1469.   p2:        Ptr);
  1470. VAR
  1471.   i:         INTEGER;
  1472.   sIdx:      Ptr;
  1473. BEGIN
  1474. IF  (ORD4(p1) < ORD4(p2)) THEN
  1475.   sIdx := p1
  1476. ELSE
  1477.   sIdx := p2;
  1478. FOR i := 1 TO ABS(ORD4(p2)-ORD4(p1))+1 DO
  1479.   BEGIN
  1480.   sIdx^ := 0;
  1481.   INC(LONGINT(sIdx));
  1482.   END;
  1483. END;
  1484. {*******************************************}
  1485. END.